﻿using PP.PaintLib;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;

namespace MyPaint
{
    public partial class FrmScreenSnap : Form
    {
        #region 字段

        private Image sourseImage;//全屏幕截图
        private Image backImage;//做灰度化处理，作为窗体的底图
        private Bitmap snapBmp;//截图（可编辑）

        private Point snapStartPoint = Point.Empty;//鼠标一开始按下的坐标
        private int snapX, snapY;//记录最小坐标

        //鼠标是否在截图区域内
        private bool IsInSnapArea => new Rectangle(snapX, snapY, SnapWidth, SnapHeight).Contains(MousePosition);
        private Cursor mouseCursor = Cursors.SizeAll;//记录鼠标图标

        private bool isMoveSnapArea = false;//优先级：1 在移动截图区域中
        private bool isEditSnapArea = false;//优先级：1 在编辑截图区域中

        private bool isDrawing = false;//优先级：3 是否重绘截图区域
        private bool isInit = true;//优先级：2 是否在初始化时选取接近最大化的截图区域
        private bool isRecordMouseStatus = true;//优先级：2 是否实时记录鼠标状态
        private SnapTool snapTool;//截图工具

        #endregion

        #region 属性

        private int _snapWidth;
        /// <summary>
        /// 截取区域的宽度(>=1)
        /// </summary>
        public int SnapWidth
        {
            get { return _snapWidth; }
            set
            {
                value = value > 0 ? value : value + 1;
                _snapWidth = value;
            }
        }

        private int _snapHeight;
        /// <summary>
        /// 截图区域的高度（>=1）
        /// </summary>
        public int SnapHeight
        {
            get { return _snapHeight; }
            set
            {
                value = value > 0 ? value : value + 1;
                _snapHeight = value;
            }
        }

        #endregion

        /// <summary>
        /// 构造函数+0
        /// </summary>
        public FrmScreenSnap()
        {
            InitializeComponent();

            //减少窗体重绘闪烁
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            //添加截图工具+事件
            snapTool = new SnapTool() { Location = new Point(-100, -100) };
            snapTool.SnapEvent += SnapToolEvent;
            this.Controls.Add(snapTool);

            this.WindowState = FormWindowState.Maximized;//窗体最大化
            this.TopMost = true;//窗口置顶
            this.FormBorderStyle = FormBorderStyle.None;//窗口无边框

            sourseImage = PPImage.GetImageFromScreen();//全屏幕图       
            backImage = PPImage.FilterLightImage(sourseImage, -64);//灰色底图
            this.BackgroundImage = backImage;//灰色底图放到控件背景上
            this.BackgroundImageLayout = ImageLayout.Stretch;//全图显示

            //鼠标事件
            this.MouseUp += MouseUpEvent;
            this.MouseMove += MouseMoveEvent;
            this.MouseDown += MouseDownEvent;

            //键盘事件
            this.KeyUp += KeyUpEvent;

            //绘图事件
            this.Paint += PaintEvent;

            //析构事件
            this.Disposed += DisposedEvent;
        }

        #region 鼠标事件

        private void MouseDownEvent(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (isMoveSnapArea)//移动截图区域中
                {
                    return;
                }

                if (isEditSnapArea)//编辑截图区域中
                {
                    return;
                }

                //重绘截图区域中
                snapStartPoint = e.Location;
                snapTool.Visible = false;
                isDrawing = true;
                isRecordMouseStatus = true;
                isInit = false;
            }

            if (e.Button == MouseButtons.Right)
            {
                SnapSaveTo();
            }
        }
        private void MouseMoveEvent(object sender, MouseEventArgs e)
        {
            if (isDrawing || isRecordMouseStatus)
            {
                this.Invalidate();
            }

            ////设置鼠标图标
            //this.Cursor = snapTool.Cursor = IsInSnapArea ? mouseCursor : Cursors.Default;
        }
        private void MouseUpEvent(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if(isEditSnapArea)//编辑截图区域中
                {
                    return;
                }

                Point p = MousePosition;
                p.X -= Math.Min(p.X, snapTool.Width);
                p.Y -= p.Y > this.Height - snapTool.Height ? snapTool.Height : 0;
                snapTool.Location = p;
                //绘图工具-这个第一次显示会触发界面重绘-bug
                snapTool.Visible = true;

                isDrawing = false;
                isRecordMouseStatus = false;

                //绘制截图
                snapBmp?.Dispose();
                snapBmp = new Bitmap(SnapWidth, SnapHeight);
                using (Graphics g = Graphics.FromImage(snapBmp))
                {
                    g.DrawImage(sourseImage,
                        new Rectangle(0, 0, snapBmp.Width, snapBmp.Height), //目的
                        new Rectangle(snapX, snapY, SnapWidth, SnapHeight),//源
                        GraphicsUnit.Pixel);
                }
            }
        }

        #endregion

        #region 键盘事件

        /// <summary>
        /// 键盘按起（不适用组合键）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void KeyUpEvent(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                this.Close();
            }
        }

        #endregion

        #region 绘图事件

        private void PaintEvent(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            //重新拷贝灰色底图，清除掉每次MoveIn事件重绘的图像
            g.DrawImage(backImage,
                new Rectangle(0, 0, this.Width, this.Height), //目的
                new Rectangle(0, 0, backImage.Width, backImage.Height),//源
                GraphicsUnit.Pixel);

            //初始化绘制截图区域
            if (isInit)
            {
                //选取截图区域
                SnapWidth = this.Width;
                SnapHeight = this.Height - 30;
                var rect = new Rectangle(0, 0, SnapWidth, SnapHeight);
                DrawSnapAndString(g, rect);
            }

            //鼠标按下、移动 绘制截图区域
            if (isDrawing)
            {
                //选取截图区域
                SnapWidth = Math.Abs(snapStartPoint.X - MousePosition.X);
                SnapHeight = Math.Abs(snapStartPoint.Y - MousePosition.Y);     
                snapX = Math.Min(snapStartPoint.X, MousePosition.X);
                snapY = Math.Min(snapStartPoint.Y, MousePosition.Y);
                var rect = new Rectangle(snapX, snapY, SnapWidth, SnapHeight);

                DrawSnapAndString(g, rect);
            }

            //绘制文本-右下角-实时记录鼠标状态
            if (isRecordMouseStatus)
            {
                DrawMouseStatus(g);
            }
        }

        /// <summary>
        /// 绘制截图区域+边框+文本
        /// </summary>
        /// <param name="g">画图工具</param>
        /// <param name="rect">范围</param>
        private void DrawSnapAndString(Graphics g, Rectangle rect)
        {
            //局部重绘
            g.SetClip(rect);
            //绘制截图区域-从全屏图里面截取，绕过灰色底图
            g.DrawImage(sourseImage, rect, rect, GraphicsUnit.Pixel);

            //绘制截图区域的边框
            Pen pen = new Pen(Color.Green, 2) { DashStyle = DashStyle.Dot};
            g.DrawRectangle(pen, rect);
            g.ResetClip();

            //绘制文本-左上角
            string text_LeftTop = $"{rect.Width}ⅹ{rect.Height}";
            Point point_LeftTop = new Point(rect.X, rect.Y - 15 < 0 ? 0 : rect.Y - 15);
            g.DrawString(text_LeftTop, new Font(this.Font, FontStyle.Bold), Brushes.White, point_LeftTop);
        }

        /// <summary>
        /// 绘制文本-右下角-实时记录鼠标状态
        /// </summary>
        /// <param name="g">画图工具</param>
        private void DrawMouseStatus(Graphics g)
        {
            #region 绘制缩略图

            //绘制缩略图区域
            Bitmap bmp = new Bitmap(20, 20);
            //在sourseImage内将指定大小的图片 绘制到bmp 截取复制当前鼠标周围内容（0，0，20，20）
            Graphics g1 = Graphics.FromImage(bmp);
            g1.DrawImage(sourseImage,
                new Rectangle(0, 0, 20, 20), //目的
                new Rectangle(MousePosition.X - 10, MousePosition.Y - 10, 20, 20),//源
                GraphicsUnit.Pixel);

            //放大图片（会失真，造成缩略效果）
            Image thumbnail = bmp.GetThumbnailImage(100, 100, null, new IntPtr());

            //画放大图
            g1.DrawImage(thumbnail, 10, 10, thumbnail.Width, thumbnail.Height);

            //绘制缩略图里面的田字格
            Graphics g2 = Graphics.FromImage(thumbnail);
            g2.DrawRectangle(Pens.Green, 0, 0, thumbnail.Width - 1, thumbnail.Height - 1);
            g2.DrawLine(Pens.Green, new Point(thumbnail.Width / 2, 0), new Point(thumbnail.Width / 2, thumbnail.Height));//画竖线
            g2.DrawLine(Pens.Green, new Point(0, thumbnail.Height / 2), new Point(thumbnail.Width, thumbnail.Height / 2));//画横线

            //缩略图坐标
            Point p = new Point();
            p.X = MousePosition.X + 10;
            p.Y = MousePosition.Y + 10;
            p.X -= p.X > this.Width - 100 ? 100 + 20 + 10 + 15 : 0;
            p.Y -= p.Y > this.Height - 100 ? 100 + 20 + 10 + 15 : 0;

            //局部重绘
            g.SetClip(new Rectangle(p, thumbnail.Size));
            //在画布上绘制缩略图
            g.DrawImage(thumbnail, p);
            g.ResetClip();

            //回收内存
            bmp.Dispose();
            g1.Dispose();
            g2.Dispose();
            thumbnail.Dispose();

            #endregion

            //绘制鼠标的坐标
            string text_MousePostion = $"POS: ({MousePosition.X},{MousePosition.Y})";
            Point point_MousePostion = new Point(p.X, p.Y + 10 + 100);

            //绘制鼠标的坐标的背景
            var text_backColor = new SolidBrush(Color.FromArgb(128, 0, 0, 0));
            g.FillRectangle(text_backColor, new RectangleF(point_MousePostion, g.MeasureString(text_MousePostion, new Font(this.Font, FontStyle.Bold))));
            g.DrawString(text_MousePostion, new Font(this.Font, FontStyle.Bold), Brushes.White, point_MousePostion);

            //在全屏图中
            Bitmap tempBmp = new Bitmap(sourseImage);
            //获取鼠标所在点位的颜色
            Color mouseColor = tempBmp.GetPixel(MousePosition.X, MousePosition.Y);
            //绘制颜色
            string text_RGB = $"RGB: ({mouseColor.R},{mouseColor.G},{mouseColor.B})";
            Point point_RGB = new Point(point_MousePostion.X, point_MousePostion.Y + 15);
            g.FillRectangle(text_backColor, new RectangleF(point_RGB, g.MeasureString(text_RGB, new Font(this.Font, FontStyle.Bold))));
            g.DrawString(text_RGB, new Font(this.Font, FontStyle.Bold), Brushes.White, point_RGB);

            //回收内存
            tempBmp.Dispose();
            text_backColor.Dispose();
        }

        #endregion

        #region 析构事件

        /// <summary>
        /// 析构函数-统一回收需要手动回收的内容
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DisposedEvent(object sender, EventArgs e)
        {
            //回收内存
            sourseImage?.Dispose();
            backImage?.Dispose();
            snapBmp?.Dispose();

            GC.Collect();
        }

        #endregion

        /// <summary>
        /// 控件回传-执行命令
        /// </summary>
        /// <param name="order">命令</param>
        private void SnapToolEvent(string order)
        {
            isEditSnapArea = true;//标记 编辑截图区域中

            switch (order)
            {
                case "butRejustRectangleWidth":
                    break;
                case "butRejustCircleWidth":
                    break;
                case "butRedArrow":
                    break;
                case "btnDrawLineTo":
                    break;
                case "btnDrawMosaic":
                    break;
                case "btnWriting":

                    break;
                case "btnDrawUndo":
                    break;
                case "btnDrawSave"://保存截图到文件
                    SnapSaveTo("File");
                    break;
                case "btnDrawCancel"://取消截图
                    KeyUpEvent(null, new KeyEventArgs(Keys.Escape));
                    break;
                case "btnDrawDone"://保存截图到剪切板
                    SnapSaveTo();
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 保存截图到...
        /// </summary>
        /// <param name="snapVector">绘制截图的载体</param>
        private void SnapSaveTo(string snapVector = "Clipboard")
        {
            //顶部弹窗提示
            FrmMessageBox frmMessage = null;

            if (snapBmp == null)
            {
                //绘制截图
                snapBmp = new Bitmap(SnapWidth, SnapHeight);
                using (Graphics g = Graphics.FromImage(snapBmp))
                {
                    g.DrawImage(sourseImage,
                        new Rectangle(0, 0, snapBmp.Width, snapBmp.Height), //目的
                        new Rectangle(snapX, snapY, SnapWidth, SnapHeight),//源
                        GraphicsUnit.Pixel);
                }
            }

            switch (snapVector)
            {
                case "Clipboard":

                    Clipboard.SetImage(snapBmp);//截图保存到剪切板中

                    this.Close();

                    frmMessage = new FrmMessageBox(this.Location, this.Width, "截图已保存至剪贴板", Color.Green);
                    frmMessage.Show();

                    break;

                default:

                    SaveFileDialog sfd = new SaveFileDialog();
                    sfd.Filter = "png文件 (*.png)|*.png|jpg文件 (*.jpg; *.jpeg)|*.jpg; *.jpeg";
                    sfd.RestoreDirectory = true;//耗时非常严重
                    sfd.FileName = $"PP.Paint截图_{DateTime.Now.ToString("yyyyMMddHHmmssff")}.png";
                    if (sfd.ShowDialog() == DialogResult.OK)
                    {
                        string imagePath = sfd.FileName;
                        string fileExten = Path.GetExtension(imagePath);
                        switch (fileExten)
                        {
                            case ".jpg":
                            case ".jpeg":

                                snapBmp.Save(imagePath, ImageFormat.Jpeg);

                                break;

                            case ".png":

                                snapBmp.Save(imagePath, ImageFormat.Png);

                                break;
                            default:

                                snapBmp.Save(imagePath, ImageFormat.Png);

                                break;
                        }

                        this.Close();

                        frmMessage = new FrmMessageBox(this.Location, this.Width, "截图已保存", Color.Green);
                        frmMessage.Show();

                    }

                    break;
            }
        }
    }
}
